using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Admin.NET.Application.Entity.Business;
using Admin.NET.Application.Enums;
using Admin.NET.Application.EventBus;
using Admin.NET.Application.Mqtt.mqttresponse;
using Admin.NET.Application.Service.ApiJob.Dto;
using Admin.NET.Application.Service.Electricity;
using Admin.NET.Application.Service.Electricity.Dto;
using Admin.NET.Application.Util;
using Admin.NET.Core;
using Furion;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.EventBus;
using Furion.FriendlyException;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

namespace Admin.NET.Application.Service.ApiJob;

[ApiDescriptionSettings(new string[] { "业务应用" }, Order = 100)]
public class ApiJobOperateService : IDynamicApiController, ITransient, IPrivateDependency
{
	private readonly SqlSugarRepository<ApiJobInfo> _rep;

	private readonly SqlSugarRepository<ApiJobDetial> _repJob;

	private readonly IEventPublisher _eventPublisher;

	public ApiJobOperateService(SqlSugarRepository<ApiJobInfo> rep, SqlSugarRepository<ApiJobDetial> repJob, IEventPublisher eventPublisher)
	{
		_rep = rep;
		_repJob = repJob;
		_eventPublisher = eventPublisher;
	}

	/// <summary>
	/// 任务执行
	/// </summary>
	/// <returns></returns>
	[HttpPost("/job/operateJob")]
	[AllowAnonymous]
	[NonUnify]
	public async Task<dynamic> JobExec(ApiJobExecIn jobInfo)
	{
		try
		{
			List<ApiJobDetial> apiJobDetials;
			long jobid;
			ApiJobInfo job;
			DateTime now;
			if (jobInfo.operateCode == 3)
			{
				apiJobDetials = new List<ApiJobDetial>();
				jobid = jobInfo.Id;
				job = (from u in _rep.AsQueryable()
					where u.Id == jobid
					select u).First();
				now = DateTime.Now;
				List<long> deviceIdarr = jobInfo.meterInfo.Select((MeterJobInfo u) => u.Id).ToList();
				await (from it in _rep.Context.Updateable<ElectricMeter>().SetColumns((ElectricMeter it) => it.PriceRuleId == jobInfo.MeterRuleId)
					where deviceIdarr.Contains(it.Id)
					select it).ExecuteCommandAsync();
				foreach (MeterJobInfo item in jobInfo.meterInfo)
				{
					ApiJobDetial detial = new ApiJobDetial
					{
						ApiJobId = jobid,
						DeviceName = item.Name,
						Imei = item.Imei,
						JobExecTime = now,
						OperateCode = jobInfo.Code,
						TenantId = job.TenantId
					};
					bool sucess = true;
					detial.State = sucess;
					apiJobDetials.Add(detial);
				}
				_repJob.Context.Insertable(apiJobDetials).ExecuteCommand();
				return "ok";
			}
			apiJobDetials = new List<ApiJobDetial>();
			jobid = jobInfo.Id;
			job = (from u in _rep.AsQueryable()
				where u.Id == jobid
				select u).First();
			now = DateTime.Now;
			if (job == null)
			{
				return false;
			}
			foreach (MeterJobInfo item in jobInfo.meterInfo)
			{
				ApiJobDetial detial = new ApiJobDetial
				{
					ApiJobId = jobid,
					DeviceName = item.Name,
					Imei = item.Imei,
					JobExecTime = now,
					OperateCode = jobInfo.Code,
					TenantId = job.TenantId
				};
				bool sucess;
				if (jobInfo.Code == 0)
				{
					BaseIdInput baseIdInput = new BaseIdInput
					{
						Id = item.Id
					};
					sucess = await ReadingMeter(baseIdInput);
				}
				else if (jobInfo.Code == 1)
				{
					InputSwitch inputSwitch = new InputSwitch
					{
						GateStatus = 1,
						Id = item.Id
					};
					sucess = await Switch(inputSwitch);
				}
				else
				{
					InputSwitch inputSwitch = new InputSwitch
					{
						GateStatus = 0,
						Id = item.Id
					};
					sucess = await Switch(inputSwitch);
				}
				detial.State = sucess;
				apiJobDetials.Add(detial);
			}
			_repJob.Context.Insertable(apiJobDetials).ExecuteCommand();
		}
		catch (Exception)
		{
		}
		return "ok";
	}

	/// <summary>
	/// 拉合闸
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	private async Task<bool> Switch(InputSwitch input)
	{
		try
		{
			ElectricMeter device = await (from u in _rep.Context.Queryable<ElectricMeter>()
				where u.Id == input.Id
				select u).FirstAsync();
			bool isdtu = false;
			if (device != null)
			{
				if (input.GateStatus == 1 && device.IsElectricityProtection)
				{
					DateTime now = DateTime.Now;
					if (!device.ElectricityProtectionBegin.HasValue && !device.ElectricityProtectionEnd.HasValue)
					{
						throw Oops.Bah("保电期间无法拉闸");
					}
					int num;
					if (!device.ElectricityProtectionBegin.HasValue)
					{
						DateTime value = now;
						DateTime? electricityProtectionEnd = device.ElectricityProtectionEnd;
						num = ((value < electricityProtectionEnd) ? 1 : 0);
					}
					else
					{
						num = 0;
					}
					if (num != 0)
					{
						throw Oops.Bah("保电期间无法拉闸");
					}
					int num2;
					if (!device.ElectricityProtectionEnd.HasValue)
					{
						DateTime value = now;
						DateTime? electricityProtectionEnd = device.ElectricityProtectionBegin;
						num2 = ((value > electricityProtectionEnd) ? 1 : 0);
					}
					else
					{
						num2 = 0;
					}
					if (num2 != 0)
					{
						throw Oops.Bah("保电期间无法拉闸");
					}
					int num3;
					if (device.ElectricityProtectionBegin.HasValue && device.ElectricityProtectionEnd.HasValue && device.ElectricityProtectionEnd >= now)
					{
						DateTime value = now;
						DateTime? electricityProtectionEnd = device.ElectricityProtectionBegin;
						num3 = ((value > electricityProtectionEnd) ? 1 : 0);
					}
					else
					{
						num3 = 0;
					}
					if (num3 != 0)
					{
						throw Oops.Bah("保电期间无法拉闸");
					}
				}
				string imei;
				if (device.ProtocolType == 0)
				{
					imei = device.Sn;
				}
				else
				{
					isdtu = true;
					Admin.NET.Application.Collector collector = await (from u in _rep.Context.Queryable<Admin.NET.Application.Collector>()
						where (long?)u.Id == device.CollectorId
						select u).FirstAsync();
					if (collector == null)
					{
						throw Oops.Oh(ErrorCodeEnum.xg1002);
					}
					if (collector.Status == 0)
					{
						throw Oops.Oh(ErrorCodeEnumEx.X1003);
					}
					imei = collector.Imei;
				}
				long TenantId = device.TenantId.Value;
				var (pluginService, currentModel) = AggrementPluginUtil.GetPlugin(device, isdtu);
				if (currentModel.HasGate == 0 || string.IsNullOrWhiteSpace(currentModel.PowerOffCMD) || string.IsNullOrWhiteSpace(currentModel.PowerOnCMD))
				{
					throw Oops.Oh("当前电表不支持拉合闸");
				}
				if (input.GateStatus == 1)
				{
					pluginService.PowerOff(imei, device.LowAddr, currentModel.Code, currentModel.PowerOffCMD);
				}
				else
				{
					pluginService.PowerOn(imei, device.LowAddr, currentModel.Code, currentModel.PowerOnCMD);
				}
				int code = ((device.GateStatus == 0) ? 1 : 0);
				await (from u in _rep.Context.Updateable<ElectricMeter>().SetColumns((ElectricMeter u) => u.GateStatus == code).SetColumns((ElectricMeter u) => u.SignalStatus == 1)
					where u.Id == device.Id
					select u).ExecuteCommandAsync();
				long orgId = 0L;
				long.TryParse(App.User?.FindFirst("OrgId")?.Value, out orgId);
				long userId = 0L;
				long.TryParse(App.User?.FindFirst("UserId")?.Value, out userId);
				JsonConvert.SerializeObject(input);
				if (device.RoomId.HasValue)
				{
					Room room = await (from w in _rep.Context.Queryable<Room>()
						where w.TenantId == (long?)TenantId && (long?)w.Id == device.RoomId
						select w).FirstAsync();
					if (room != null && room.OwnerId.HasValue)
					{
						Owner owner = await (from w in _rep.Context.Queryable<Owner>()
							where w.TenantId == (long?)TenantId && (long?)w.Id == room.OwnerId
							select new Owner
							{
								Email = w.Email,
								Id = w.Id,
								AppId = w.AppId,
								OpenId = w.OpenId,
								PhoneNumber = w.PhoneNumber,
								Name = w.Name
							}).FirstAsync();
						if (owner != null)
						{
							string gatename = ((input.GateStatus == 1) ? "断闸" : "合闸");
							BillNoticePayload billNoticePayload = new BillNoticePayload
							{
								Body = $"您的电表：{device.Name}({device.Sn})已{gatename}。",
								Subject = "电表" + gatename,
								GateStatus = input.GateStatus,
								Owners = new List<Owner> { owner },
								MeterName = device.Name,
								RoomId = room.Id,
								RoomName = room.Name,
								Path = "/userPage/meterDetail/meterDetail?meterId=" + device.Id
							};
							EventPayload payload = new EventPayload
							{
								Data = JsonConvert.SerializeObject(billNoticePayload),
								TenantId = TenantId
							};
							for (int i = 0; i < 4; i++)
							{
								_eventPublisher.PublishAsync($"{i}:SendGateNotice", payload).Wait();
							}
						}
					}
				}
				return true;
			}
			throw Oops.Oh(ErrorCodeEnum.xg1002);
		}
		catch (Exception)
		{
			return false;
		}
	}

	private async Task<bool> ReadingMeter(BaseIdInput input)
	{
		try
		{
			bool isdtu = false;
			ElectricMeter device = await (from u in _rep.Context.Queryable<ElectricMeter>()
				where u.Id == input.Id
				select u).FirstAsync();
			int newtype = 0;
			if (device != null)
			{
				string imei;
				if (device.ProtocolType == 0)
				{
					imei = device.Sn;
				}
				else
				{
					isdtu = true;
					newtype = 1;
					Admin.NET.Application.Collector collector = await (from u in _rep.Context.Queryable<Admin.NET.Application.Collector>()
						where (long?)u.Id == device.CollectorId
						select u).FirstAsync();
					if (collector == null)
					{
						throw Oops.Bah("未有效关联采集设备");
					}
					if (collector.Status == 0)
					{
						throw Oops.Oh(ErrorCodeEnumEx.X1003);
					}
					imei = collector.Imei;
				}
				(IAggrementPlugin, BrandModel) plugin = AggrementPluginUtil.GetPlugin(device, isdtu);
				IAggrementPlugin pluginService = plugin.Item1;
				BrandModel currentModel = plugin.Item2;
				string body = ((!device.PriceRuleId.HasValue || !(device.PriceRuleId > 0)) ? pluginService.ReadCombinedTotalE(imei, device.LowAddr, currentModel.Code) : ((!(await (from u in _rep.Context.Queryable<ElectricityPriceRule>()
					where (long?)u.Id == device.PriceRuleId && u.Type == 1
					select u).AnyAsync())) ? pluginService.ReadCombinedTotalE(imei, device.LowAddr, currentModel.Code) : pluginService.ReadCombinedAllTotal(imei, device.LowAddr, currentModel.Code)));
				if (!string.IsNullOrEmpty(body))
				{
					Dictionary<string, UploadMqttInfo> dic = new Dictionary<string, UploadMqttInfo> { 
					{
						device.LowAddr,
						new UploadMqttInfo
						{
							State = ((device.GateStatus == 1) ? "0000" : "1111"),
							Alltotal = body,
							TotalE = body
						}
					} };
					EPowerService ePowerService = new EPowerService();
					await ePowerService.MeterUpload(imei, newtype, dic);
					return true;
				}
				throw Oops.Bah("抄表失败，请检查表地址和通讯线");
			}
			throw Oops.Oh(ErrorCodeEnum.xg1002);
		}
		catch (Exception)
		{
			return false;
		}
	}
}
